{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Express sklearn pipeline as codeflare pipeline\n",
    "\n",
    "Reference: https://scikit-learn.org/stable/auto_examples/compose/plot_digits_pipe.html#sphx-glr-auto-examples-compose-plot-digits-pipe-py\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# Pipelining: chaining a PCA and a logistic regression\n",
    "\n",
    "The PCA does an unsupervised dimensionality reduction, while the logistic\n",
    "regression does the prediction.\n",
    "\n",
    "We use a GridSearchCV to set the dimensionality of the PCA\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Automatically created module for IPython interactive environment\n",
      "Best parameter (CV score=0.920):\n",
      "{'logistic__C': 0.046415888336127774, 'pca__n_components': 45}\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAAGoCAYAAAATsnHAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAABOwUlEQVR4nO3dd5xdVbn/8c83k55MCJBeyEAICQGpY6gCiqFDRKWD9BCvKIjeS0AvoljQKyIqP0LoiFJUkFAEYgQRaUkglFRCSEiDFAzp/fn9sfeEk2Eyc2bOzJxzZr7v1+u8ztll7fOsSTJP9lprr6WIwMzMrNC0yHcAZmZmVXGCMjOzguQEZWZmBckJyszMCpITlJmZFaSW+Q6gMXTp0iXKysryHYaZARs2bQagVYn/f9ycTJw4cUlEdK1NmWaRoMrKypgwYUK+wzAza7YkzaltGf8Xxswa1XPTF/Hc9EX5DsOKQLO4gzKzwnHLc+8CcMTAbnmOxAqdE5SZNarfnrlvvkOwIuEEZWaNqltp23yHYEXCCSrDjWNn8O2hu+U7DGvGNm/ezLx581i1alW+Q2kwazdsAqBtq5I8R2L1rUOHDvTp04cWLepneIMTVIabxr3jBGV5tWTJEiQxcODAevtHXmjeXbwSgP5dO+Y5EqtPmzdvZv78+SxZsoRu3eqnf7Fp/gswK1LLli2je/fuTTY5AfTboT39dmif7zCsnrVo0YLu3bvz8ccf19s1m/0d1I1jZ3DTuHe2bJeNfAKAy44c4Lspa3SbNm2iVatW+Q6jQbX0A7pNVqtWrdi4cWO9Xa/ZJ6hvD91tSyIqG/kEs68/Ps8RWXMnKd8hNKiP16wHYLt2rfMcidW3+v672+wTlJk1riUrnaAsO77XznDZkQPyHYJZk1e2Y3vKdnQfVF0dccQR3H777fkOo1E4QWVwn5NZwytp0YKSJjwIpMJzzz1Hnz598h1GUWv6f0vMrKAsW72eZavX5zsMKwJ5SVCSjpE0XdJMSSOrOD5I0kuS1kn6bhXHSyS9LunxxonYzMrKyvjlL3/JXnvtxXbbbcdpp53G2rVrayz36KOPss8++9CpUyf69+/Pw489wdJV61mwYAEnnXQSO+ywA7vuuiu33XbbljLXXnstp5xyCmeffTalpaV85jOfYcaMGfzsZz+jW7du9O3bl2eeeWbL+UcccQRXXXUVQ4YMYbvttmPYsGF89NFHW46PGTOGPfbYg86dO3PEEUcwderUrOv1+OOPs88++9C5c2cOPvhg3nzzzRrLrlq1imOPPZYFCxbQsWNHOnbsyIIFC3j11VcpLy+nU6dOdO/enSuuuCLrn9tTTz215dicOXM45JBDKC0t5aijjmLJkiVZ1fXnP/85vXv3prS0lIEDBzJu3DggeYbp+uuvp3///uy4446ceuqpW35+s2fPRhL33HMPO+20E126dOEnP/lJjX/u9SIiGvUFlADvArsArYE3gMGVzukGfBb4CfDdKq5xBfBH4PFsvnP//fcPs2IwZcqUrbZPHfViPDT+/YiIWL9xU5w66sV4+LW5ERGxet3GOHXUizFm0vyIiPh4zfo4ddSL8be3FkRExNKV6+LUUS/G2MkfRETEh8vXxKmjXoxnp30YERHz/7O6VrH169cvPvvZz8b8+fNj6dKlMWjQoLjllluqLfPKK69Ep06d4plnnolNmzbFvHnzYvLkKbFp0+Y47LDD4utf/3qsWbMmXn/99ejSpUv8/e9/j4iIH/zgB9GmTZt46qmnYsOGDXHOOedEWVlZ/PjHP47169fH6NGjo6ysbMv3HH744dGrV6946623YuXKlfHlL385zjrrrIiImD59erRv3z6eeeaZWL9+ffz85z+P/v37x7p162qs18SJE6Nr167x8ssvx8aNG+Puu++Ofv36xdq1a2ss++yzz0bv3r23+nkceOCBce+990ZExIoVK+Kll17K+uc2derULXXdZZddYvr06bF69eo4/PDD48orr6yxrtOmTYs+ffrE/PnJ35f33nsvZs6cGRERN954YxxwwAExd+7cWLt2bQwfPjxOP/30LecBcdFFF8Xq1atj0qRJ0bp160/9Xa2wrf3AhKhlvsjHHdQQYGZEzIqI9cADwLDMEyJiUUSMBzZULiypD3A80Dx6Cc0KyLe+9S169erFDjvswIknnsikSZOqPf+OO+7gggsuYOjQobRo0YLevXszePDuzJ8/jxdeeIGf//zntG3bln322YeLLrqI3//+91vKfu5zn+Poo4+mZcuWnHLKKSxevJiRI0fSqlUrTj/9dGbPns2yZcu2nH/OOeew55570qFDB6677joeeughNm3axIMPPsjxxx/P0KFDadWqFd/97ndZs2YNL774Yo31uu2227jkkks44IADKCkp4dxzz6VNmza8/PLLdfqZtGrVipkzZ7JkyRI6duzIgQcemPXPbdCgQVuOn3/++ey22260a9eOU089dct3VlfXkpIS1q1bx5QpU9iwYQNlZWX0798fgFtvvZWf/OQn9OnThzZt2nDttdfy5z//eatnmn7wgx/Qrl079t57b/bee2/eeOONav/s60M+ElRvYG7G9rx0X7Z+DfwPsLkeYzIrSA9echCnlPcFkhVoH7zkIE7eN+l4b9e6hAcvOYgT9+4FQKe2rXjwkoM4Zs+eAOzQoTUPXnIQXxzcHUgmaX3wkoO2LHPRq3O7WsfTo0ePLZ/bt2/PypUrqz1/7ty5W34JVvjP6vVMmzWHHXbYgdLS0i37+/Xrx/z587dsd+/efcvndu3a0aVLF0pKSrZsA1t9f9++fbe61oYNG1iyZAkLFiygX79+W461aNGCvn37bvVd26rXnDlzuOGGG+jcufOW19y5c1mwYEGdfiZ33HEHM2bMYNCgQXz2s5/l8cer7qWo6ueWaVvfWV1dd911V379619z7bXX0q1bN04//fQt9ZgzZw4nn3zyljruvvvulJSU8OGHH9apnvUlHwmqqie5IquC0gnAooiYmMW5wyVNkDRh8eLFtY3RzOpB3759effdd7fa99Gq9bTdrgsfffQRK1as2LL//fffp3fv2vxfdWtz537y/97333+fVq1a0aVLF3r16sWcOZ8s5hoRzJ07N6vv6tu3L9/73vdYtmzZltfq1as544wzaixb1UOrAwYM4P7772fRokVceeWVfPWrX61yYuCqfm7ZqKmuZ555Ji+88AJz5sxBEldeeeWW7/vb3/62VT3Xrl2b059HfchHgpoH9M3Y7gMs2Ma5lR0CnCRpNknT4Bck3VfViRExOiLKI6K8a9eudQ72xrEz6lzWrLm78MILueuuuxg3btyWyUTXLZnLIXsP5OCDD+aqq65i7dq1vPnmm9xxxx2cddZZdf6u++67jylTprB69WquueYavvrVr1JSUsKpp57KE088wbhx49iwYQM33HADbdq04eCDD67xmhdffDGjRo3ilVdeISJYtWoVTzzxxFaJdVu6d+/O0qVLt5qb7r777mPx4sW0aNGCzp07A2y5K8xU1c9t2rRpNX5ndXWdPn06//jHP1i3bh1t27alXbt2W757xIgRfO9739uS3BYvXsyjjz5a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\n",
      "text/plain": [
       "<Figure size 432x432 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "print(__doc__)\n",
    "\n",
    "\n",
    "# Code source: Gaël Varoquaux\n",
    "# Modified for documentation by Jaques Grobler\n",
    "# License: BSD 3 clause\n",
    "\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "\n",
    "from sklearn import datasets\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "\n",
    "# Define a pipeline to search for the best combination of PCA truncation\n",
    "# and classifier regularization.\n",
    "pca = PCA()\n",
    "# set the tolerance to a large value to make the example faster\n",
    "logistic = LogisticRegression(max_iter=10000, tol=0.1)\n",
    "pipe = Pipeline(steps=[('pca', pca), ('logistic', logistic)])\n",
    "\n",
    "X_digits, y_digits = datasets.load_digits(return_X_y=True)\n",
    "\n",
    "# Parameters of pipelines can be set using ‘__’ separated parameter names:\n",
    "param_grid = {\n",
    "    'pca__n_components': [5, 15, 30, 45, 64],\n",
    "    'logistic__C': np.logspace(-4, 4, 4),\n",
    "}\n",
    "search = GridSearchCV(pipe, param_grid, n_jobs=-1)\n",
    "search.fit(X_digits, y_digits)\n",
    "print(\"Best parameter (CV score=%0.3f):\" % search.best_score_)\n",
    "print(search.best_params_)\n",
    "\n",
    "# Plot the PCA spectrum\n",
    "pca.fit(X_digits)\n",
    "\n",
    "fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, figsize=(6, 6))\n",
    "ax0.plot(np.arange(1, pca.n_components_ + 1),\n",
    "         pca.explained_variance_ratio_, '+', linewidth=2)\n",
    "ax0.set_ylabel('PCA explained variance ratio')\n",
    "\n",
    "ax0.axvline(search.best_estimator_.named_steps['pca'].n_components,\n",
    "            linestyle=':', label='n_components chosen')\n",
    "ax0.legend(prop=dict(size=12))\n",
    "\n",
    "# For each number of components, find the best classifier results\n",
    "results = pd.DataFrame(search.cv_results_)\n",
    "\n",
    "components_col = 'param_pca__n_components'\n",
    "best_clfs = results.groupby(components_col).apply(\n",
    "    lambda g: g.nlargest(1, 'mean_test_score'))\n",
    "\n",
    "best_clfs.plot(x=components_col, y='mean_test_score', yerr='std_test_score',\n",
    "               legend=False, ax=ax1)\n",
    "ax1.set_ylabel('Classification accuracy (val)')\n",
    "ax1.set_xlabel('n_components')\n",
    "\n",
    "plt.xlim(-1, 70)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Automatically created module for IPython interactive environment\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2021-06-10 08:55:47,730\tINFO services.py:1267 -- View the Ray dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8267\u001b[39m\u001b[22m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9226679046734757\n",
      "{'pca__3': {'copy': True, 'iterated_power': 'auto', 'n_components': 45, 'random_state': None, 'svd_solver': 'auto', 'tol': 0.0, 'whiten': False}, 'logistic__1': {'C': 0.046415888336127774, 'class_weight': None, 'dual': False, 'fit_intercept': True, 'intercept_scaling': 1, 'l1_ratio': None, 'max_iter': 10000, 'multi_class': 'auto', 'n_jobs': None, 'penalty': 'l2', 'random_state': None, 'solver': 'lbfgs', 'tol': 0.1, 'verbose': 0, 'warm_start': False}}\n",
      "0.9260058805323429\n",
      "{'pca__4': {'copy': True, 'iterated_power': 'auto', 'n_components': 64, 'random_state': None, 'svd_solver': 'auto', 'tol': 0.0, 'whiten': False}, 'logistic__1': {'C': 0.046415888336127774, 'class_weight': None, 'dual': False, 'fit_intercept': True, 'intercept_scaling': 1, 'l1_ratio': None, 'max_iter': 10000, 'multi_class': 'auto', 'n_jobs': None, 'penalty': 'l2', 'random_state': None, 'solver': 'lbfgs', 'tol': 0.1, 'verbose': 0, 'warm_start': False}}\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAAGoCAYAAAATsnHAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAABP0klEQVR4nO3deXxU5dn/8c+XsO8qi5AgUUQQRVEj4lKltbgr1brgVnekj7ba5alo+1StXexi1VZ/Iq5YrUutVlREkGqtdSMoO4KIIBBk0bLJluX6/XFOwhBCciYzyZnJXO/Xa14z5z7nPnOdALk497kXmRnOOedcpmkWdwDOOedcTTxBOeecy0ieoJxzzmUkT1DOOecykico55xzGal53AE0hi5dulhhYWHcYTjnXKxKyysAaJHX+Pcm06ZNW2NmXZOpkxMJqrCwkOLi4rjDcM65nCVpSbJ1vInPOedyxBvzV/HG/FVxhxFZTtxBOeecg/ve+ASAof26xRxJNJ6gnHMuR/z5gkPiDiEpnqCccy5HdOvQOu4QkuIJKsGdkxfwg2H7xR1GVlq/fj2rVq2itLQ07lCcS0qLFi3o1q0bHTt2jDuUBvfa3JUAfHNA95gjicYTVIK7p3zsCaoe1q9fz8qVK8nPz6dNmzZIijsk5yIxMzZv3szy5csBmnySeuDfiwBPUC6HrFq1ivz8fNq2bRt3KM4lRRJt27YlPz+fkpKSJp+g7rvosLhDSErOJ6g7Jy/g7ikfV20Xjn4ZgOuO7+t3UxGVlpbSpk2buMNwrt7atGmTE83Tu7drGXcIScn5BPWDYftVJaLC0S+z+PZTY44oO3mznstmufL3d+LsFQCcdGCPmCOJJucTlHPO5YpH/rMYyJ4E5TNJJLju+L5xh+BckzV06FAefPDBuMPIaQ9cUsQDlxTFHUZknqAS+DMn5+CNN96goKAg7jBcA+jYugUdW7eIO4zIPEE551yOeHFGCS/OKIk7jMhiSVCSTpI0X9JCSaNr2N9f0juStkr6cQ378yR9KOmlxonYZbPCwkL+8Ic/cNBBB9GpUyfOO+88tmzZUme9F154gUGDBtGxY0f69OnDxIkTASgpKeGMM85g9913Z9999+WBBx6oqnPLLbdwzjnncNFFF9GhQwcGDhzIggUL+M1vfkO3bt3o1asXkyZNqjp+6NCh3HjjjQwePJhOnToxfPhwvvzyy6r948eP54ADDqBz584MHTqUefPmRb6ul156iUGDBtG5c2eOOuooZs6cWWfdr776ipNPPpmSkhLat29P+/btKSkp4f3336eoqIiOHTvSvXt3fvjDHyb9cwNYsmQJRx99NB06dOCEE05gzZo1ka71t7/9Lfn5+XTo0IF+/foxZcoUACoqKrj99tvp06cPe+yxB+eee27Vz2/x4sVIYty4cey111506dKFX/3qV3X+uTdlj7+7hMffTXpS8fiYWaO+gDzgE2AfoCUwAxhQ7ZhuwOHAr4Af13COHwJ/BV6K8p2HHXaYuYYzd+7cncrOHfO2PTP1MzMz21ZWbueOedue+2CpmZlt2lpm545528ZPX25mZus2b7Nzx7xtr8wqMTOzLzZutXPHvG2T53xuZmYr12+2c8e8ba9/tNLMzJb/d1NS8fXu3dsOP/xwW758uX3xxRfWv39/u++++2qt895771nHjh1t0qRJVl5ebsuWLbN58+aZmdmxxx5r3/3ud23z5s324YcfWpcuXey1114zM7Obb77ZWrVqZRMnTrTS0lK7+OKLrbCw0H75y1/atm3bbOzYsVZYWFj1Pccdd5z17NnTZs2aZRs3brSzzjrLLrzwQjMzmz9/vrVt29YmTZpk27Zts9/+9rfWp08f27p1a53XNW3aNOvatau9++67VlZWZo8++qj17t3btmzZUmfd119/3fLz83f4eQwZMsQee+wxMzPbsGGDvfPOO0n/3I477jjbZ599bP78+bZp0yY77rjj7IYbbqjzWj/66CMrKCiw5cuDvy+ffvqpLVy40MzM7rzzTjviiCNs6dKltmXLFhs5cqSNGDGi6jjArrzyStu0aZNNnz7dWrZsWePfV7Oa/x43NZu2ltmmrWWxfDdQbEnmizjuoAYDC81skZltA54ChiceYGarzGwqsNPABEkFwKmAP211kX3/+9+nZ8+e7L777px++ulMnz691uMfeughLr/8coYNG0azZs3Iz8+nf//+LF26lLfeeovf/va3tG7dmkGDBnHllVfyl7/8paru1772NU488USaN2/OOeecw+rVqxk9ejQtWrRgxIgRLF68mLVr11Ydf/HFF3PggQfSrl07brvtNp555hnKy8t5+umnOfXUUxk2bBgtWrTgxz/+MZs3b+btt9+u87oeeOABrr76ao444gjy8vK45JJLaNWqFe+++269fiYtWrRg4cKFrFmzhvbt2zNkyJCkfm6VLrvsMvbbbz/atGnDueeeW/WdtV1rXl4eW7duZe7cuZSWllJYWEifPn0AuP/++/nVr35FQUEBrVq14pZbbuHZZ5+lrKys6jtvvvlm2rRpw8EHH8zBBx/MjBkzav2zb8ratMyjTcu8uMOILI4ElQ8sTdheFpZFdRfwE6AijTG5NHv66iM5p6gXEKze+fTVR3LmIcGD9zYt83j66iM5/eCeQPDg9umrj6zq+rp7u5Y8ffWRVdOxdOvQmqevPrJqiYCenZMfFLznnntWfW7bti0bN26s9filS5dW/RJMVFJSwu67706HDh2qynr37l01VQ5A9+7bp5Fp06YNXbp0IS8vr2ob2OH7e/XqtcO5SktLWbNmDSUlJfTu3btqX7NmzejVq9cO37Wr61qyZAl33HEHnTt3rnotXbqUkpKSOuvW5KGHHmLBggX079+fww8/nJdeqrl1fVc/t7q+s7Zr3Xfffbnrrru45ZZb6NatGyNGjKi6jiVLlnDmmWdWXeP+++9PXl4eK1eurNd1NnXPf7iM5z9cFncYkcWRoGoaEWeRKkqnAavMbFqEY0dKKpZUvHr16mRjdDmuV69efPLJJzuV9+zZky+//JINGzZUlX322Wfk5yfzf6wdLV26/f9rn332GS1atKBLly707NmTJUu2Py8wM5YuXRrpu3r16sVPf/pT1q5dW/XatGkT559/fp11axq02rdvX5588klWrVrFDTfcwNlnn81XX31V4/fW9HOrS13XesEFF/DWW2+xZMkSJHHDDTdUfd8rr7yyw3Vu2bIlpT+Ppuyp95fy1PtL6z4wQ8SRoJYBvRK2C4Co3UqOBs6QtJigafAbkh6v6UAzG2tmRWZW1LVr13oHe+fkBfWu67LXFVdcwSOPPMKUKVOoqKhg+fLlfPTRR/Tq1YujjjqKG2+8kS1btjBz5kweeughLrzwwnp/1+OPP87cuXPZtGkTP//5zzn77LPJy8vj3HPP5eWXX2bKlCmUlpZyxx130KpVK4466qg6z3nVVVcxZswY3nvvPcyMr776ipdffnmHxLor3bt354svvmDdunU7xLh69WqaNWtG586dAaruChPt6udWl9qudf78+fzzn/9k69attG7dmjZt2lR996hRo/jpT39aldxWr17NCy+8UOf35arHrzyCx688Iu4wIks5QUk6Q9IfwtfpEapMBfpK2ltSS2AEMD7Kd5nZjWZWYGaFYb1/mtlF9Q4+gsR5+lzuGDx4MI888gg/+MEP6NSpE8cdd1zVL8Enn3ySxYsX07NnT84880xuvfVWhg0bVu/vuvjii7n00kvZc8892bJlC3/6058A6NevH48//jjf+9736NKlCy+++CIvvvgiLVvWPZ9aUVERDzzwANdeey277bYb++67L48++mikePr378/555/PPvvsQ+fOnSkpKWHixIkccMABtG/fnuuuu46nnnqK1q13Xluotp9bbWq71q1btzJ69Gi6dOnCnnvuyapVq/j1r38NwHXXXccZZ5zBCSecQIcOHRgyZAjvvfdepOvMRS3ymtEiL3tGFynoXFHPytJvCDo9PBEWnU/QU+PGOuqdQvAsKQ942Mx+JWkUgJmNkbQnUAx0JHjWtJGgp9/6hHMMJejhd1pdcRYVFVlxcXFyFxfy+fnqNm/ePPbff/+4w8hKQ4cO5aKLLuLKK6+MO5Sclwt/j/9WHDTvVT4fbkySpplZUtNYpDoX36nAIDOrCAMYB3wI1JqgzGwCMKFa2ZiEz58TNP3Vdo43gDfqE3RdfIZz51xT9Oy0oINEHAmqPtIxWWxnoHJkYac0nC92PsN5bvj1r39d1VSU6Gtf+xqvvPJKDBE517CevvrIuENISqoJ6jfAh5JeJ+iddyx13D05lyluuukmbrrpplhjeOONN2L9fucyWUoJysyelPQGwawPAm4Im+eaDJ/h3DnXVDz5/mcAnD94r5gjiaZe3Tkk9Q/fDwV6EHQdXwr0DMuaDH/mFE1FhY+bdtkrV/7+vjSzhJdmZs9ksfW9g/ohMBK4o4Z9Bnyj3hG5rNOuXTuWL19O9+7dadGiRc6sTuqyn5lRWlrKypUradeuXdzhNLgnrqx5iqpMVa8EZWYjw48nm9kO00JL2nlwhGvSCgoKWLNmDUuWLNlhDjTnskHz5s3p1KkTXbp0iTsUV02qnSTeBqo36dVU5pqwZs2a0a1bN7p16xZ3KM65WvzlncUAXHxkYaxxRFWvBBUOpM0H2kg6hO3z63UE2qYpNuecc2n02rxVQBNPUMCJwKUEg2n/mFC+AYi3365zzrkajbt8cNwhJKW+z6DGAeMkfdvM/p7mmJxzzrmUx0H9XdKpwAFA64TyX6QamHPOufR6+K1PAbj8mL1jjiSalKa1lTQGOA/4HsFzqHOA3rVWcs45F4u3P1nD25+siTuMyFLtxXeUmR0kaaaZ3SrpDuC5dATmnHMuvR685PC4Q0hKqguDVI6B2iSpJ1AKZMe9o3POuYyWaoJ6UVJn4PfAB8Bi4Mm6Kkk6SdJ8SQslja5hf39J70jaKunHCeW9JL0uaZ6kOZKuSzF+55zLGWPf/ISxb34SdxiR1buJT1IzYIqZrQX+LukloLWZraujXh5wLzCMYA6/qZLGm9nchMO+BL4PfKta9TLgR2b2gaQOwDRJk6vVdc45V4MPlqyNO4Sk1PsOKlyk8I6E7a11JafQYGChmS0ys23AU8DwaudeZWZTCZoME8tXmNkH4ecNwDyCAcON6s7JCxr7K51zLmVjLj6MMRcfFncYkaXaxDdJ0reV3Oyg+QQzn1daRj2SjKRC4BDgvV3sHympWFLx6tWrkz19rRJX23XOOdcwUu3F90OgHVAmaQtBV3Mzs4611KkpmVkyXyqpPfB34HozW1/TMWY2FhgLUFRUlNT5nXOuKfp/bywE4H+G7htzJNGkOlC3Qz2qLQN6JWwXAJEXKJHUgiA5PWFmjdal/c7JC3a4cyoc/TIQLGjoa0Y557LB3JIa/z+fsWTWuDcXkpoDC4DjgeXAVOACM5tTw7G3ABvN7A/htoBxwJdmdn3U7ywqKrLi4uLUgw8Vjn6ZxbefmrbzOedcUydpmpkVJVMn1Sa+pJlZmaRrgVeBPOBhM5sjaVS4f0w4W3oxwezoFZKuBwYABwEXA7MkTQ9PeZOZTWjky3DOOdfAGj1BAYQJZUK1sjEJnz8naPqr7i1qfobVqK47vm/cITjnXNL+FD6m+H6W/A5LOUFJOgboa2aPSOoKtDezT1MPLXP5MyfnXDZatHpj3CEkJaUEJelmoAjoBzwCtAAeB45OPTTnnHPpdNeIQ+IOISmpjoM6EzgD+ArAzEqA+vTsc84553aQaoLaZkE3QAOQ1C71kJxzzjWEP06azx8nzY87jMhSfQb1jKT7gc6SrgIuBx5IPSznnHPpVrJuS90HZZBUB+r+QdIwYD3Bc6ifm9nktETmnHMurf5wzsFxh5CUVDtJ7A38uzIpSWojqdDMFqcjOOecc7kr1WdQfwMqErbLwzLnnHMZ5rcTP+K3Ez+KO4zIUn0G1TxcMgMAM9smqWWK53TOOdcA1m7aVvdBGSTVBLVa0hlmNh5A0nBgTephOeecS7ffnHVQ3CEkJdUENQp4QtI9BFMQLQW+k3JUzjnncl6qvfg+AYaE6zMpXOXWOedcBvrVy3MB+OmpA2KOJJpUe/G1Ar4NFALNKxfWNbNfpByZc865tNpSWlH3QRkk1V58LwDDgTKC6Y4qX7WSdJKk+ZIWShpdw/7+kt6RtFXSj5Op65xzrma3fetAbvvWgXGHEVmqz6AKzOykZCpIygPuBYYRrK47VdJ4M5ubcNiXwPeBb9WjrnPOuSYg1TuotyUNTLLOYGChmS0Ku6g/RXAXVsXMVpnZVKA02brOOedqduuLc7j1xZ0WL89YqSaoY4BpYZPbTEmzJM2so04+QW+/SsvCsigi15U0UlKxpOLVq1dHPL1zzrlMkWoT38n1qFPTiriW7rpmNhYYC1BUVBT1/M4512TdfPoBcYeQlFS7mS8BkNQNaB2x2jKgV8J2AVDSCHWdc85lkZSa+CSdIelj4FPgX8Bi4JU6qk0F+kraO5wWaQQwPuJXplLXOedy2v/9Yzb/94/ZcYcRWapNfLcBQ4DXzOwQSV8Hzq+tgpmVSboWeBXIAx42szmSRoX7x0jaEygGOgIVkq4HBpjZ+prqpngNzjmXE1q3SLXbQeNSsCBuPStLxWZWJGkGcIiZVUh638wGpy/E1BUVFVlxcXHcYTjnXM6SNM3MipKpk+od1NpwmqM3CebkW0UwaNc555xLSar3e8OBzcAPgInAJ8DpqQblnHMu/W58biY3PlfXSKDMkWovvsRpjcalGItzzrkG1Lltdi3XV68EJektMztG0gZ2HIckwMysY1qic845lzY3nNQ/7hCSUq8EZWbHhO8d0huOc845F6j3MyhJzSRlT4d655zLcT/+2wx+/LcZcYcRWb2fQYVdymdI2svMPktnUM4559KvZ6eoE/5khlS7mfcA5kh6n4R1oMzsjBTP65xzLs1+eEK/uENISqoJ6ta0ROGcc85Vk2o383+lK5Bsd+fkBfxg2H5xh+Gcc7t0/VMfAnDXiENijiSaVCeLHSJpqqSNkrZJKpe0Pl3BZZO7p3wcdwjOOVerfbq2Z5+u7eMOI7JUm/juIZhR/G9AEfAdoG+qQTnnnEu/7x+fXb+eU01QmNlCSXlmVg48IuntNMSVFe6cvGCHO6fC0S8DcN3xfb25zznnUpRqgtoUrss0XdLvgBVAu7oqSToJuJtgyYwHzez2avsV7j8F2ARcamYfhPt+AFxJMIPFLOAyM9uS4nXUyw+G7VeViApHv8zi20+NIwznnIvk2r9+AMA9FxwacyTRpDpZ7MXhOa4l6GbeC/h2bRUk5QH3EiwXPwA4X9KAaoedTNBU2BcYCdwX1s0Hvg8UmdmBBAluRIrX4JxzOWFAz44M6Jk9M9Glegd1KDDBzNYTvcv5YGChmS0CkPQUwazocxOOGQ48ZsFiVe9K6iypR0LMbSSVAm3JkCXfr8uytl3nXO75n6H7xh1CUlK9gzoDWCDpL5JOlRQl4eUDSxO2l4VldR5jZsuBPwCfETQnrjOzSTV9iaSRkoolFa9evTri5dSfP3Nyzrn0SilBmdllwL4EvfguAD6R9GAd1VTTqaIcI2k3grurvYGeQDtJF+0itrFmVmRmRV27dq0jJOeca/pG/WUao/4yLe4wIktHL75SSa8QJJk2BAnkylqqLCN4VlWpgJ2b6XZ1zDeBT81sNYCk54CjgMdTuQbnnMsFh/buHHcISUl1oO5Jkh4FFgJnAw8SzM9Xm6lAX0l7hz0ARwDjqx0zHviOAkMImvJWEDTtDZHUNuzpdzwwL5VrcM65XDHy2D6MPLZP3GFEluod1KXAU8DVZrY1SgUzK5N0LfAqQS+8h81sjqRR4f4xwASCLuYLCbqZXxbue0/Ss8AHQBnwITA2xWtwzjmXgRR0lGvaioqKrLi4OO4wnHMuVleOmwrAg5cc3ujfLWmamRUlUyflZ1DOOeeyw1F9usQdQlI8QTnnXI64/Ji94w4hKamOg3LOOecaRL3uoCTNYuexS1XM7KB6R+Scc65BXPLw+wCMu3xwzJFEU98mvtPC92vC97+E7xcS9LpzzjmXYb65f7e4Q0hKvRKUmS0BkHS0mR2dsGu0pP8Av0hHcM4559Ln4iML4w4hKak+g2on6ZjKDUlHEWG5Deecc64uqfbiuwJ4WFIngmdS64DLU47KOedc2l344LsAPHHlkJgjiSalBGVm04CDJXUkGPS7Lj1hOeecS7fTDuoZdwhJSSlBSeoO/BroaWYnhwsPHmlmD6UlOuecc2lz/uC94g4hKak+g3qUYE69yrS8ALg+xXM655xzKSeoLmb2DFABwUSwQHnKUTnnnEu78+5/h/PufyfuMCJLtZPEV5L2IBy0W7k0RspROeecS7uzDyuIO4SkpHoH9UOCtZv6hOOfHgO+V1elcB2p+ZIWShpdw35J+lO4f6akQxP2dZb0rKSPJM2TdGSK1+CccznhnKJenFPUq+4DM0Sqvfg+kHQc0I9gmfb5ZlZaWx1JecC9wDCClXOnShpvZnMTDjsZ6Bu+jgDuC98B7gYmmtnZ4YKHbVO5BuecyxWl5RUAtMjLjmlY0zGb+WCgMDzXoZIws8fqOH6hmS0CkPQUwTLxiQlqOPCYBYtVvRveNfUAvgKOJVgoETPbBmxLwzU451yTd9GD7wHw9NXZ0fCUajfzvwB9gOls7xxhBE19u5IPLE3YXsb2u6PajsknWEV3NfCIpIOBacB1ZvZVPS+hQd05eQE/GLZf3GE45xwAIwZnT/MepH4HVQQMsOSW5VUNZdXr7+qY5sChwPfC5d/vBkYD/7fTl0gjgZEAe+0VT9//u6d87AnKOZcxzjwktzpJzAb2TLLOMiAxjRcAJRGPWQYsM7P3wvJnCRLWTsxsrJkVmVlR165dkwzROeeans3bytm8LXtGAqV6B9UFmCvpfWBrZaGZnVFLnalAX0l7A8uBEcAF1Y4ZD1wbPp86AlhnZisAJC2V1M/M5gPHs+Ozq9jdOXkBd0/5uGq7cPTLAFx3fF+/m3LOxerSR4L1oHLiGRRwS7IVzKxM0rUEM1DkAQ+b2RxJo8L9Y4AJwCnAQoL1pS5LOMX3gCfCHnyLqu2L3Q+G7VeViApHv8zi20+NOSLnnAtcNKR33CEkJdVu5v+qZ70JBEkosWxMwmdj+2KI1etOJ3j25ZxzLgmnH5wDk8VKesvMjpG0gR07OIggv3RMS3RZ7rrj+8YdgnPOVVm/JRim2rF1i5gjiaa+K+oeE753SG84TYs/c3LOZZKrxhUDufMMCgBJ3YDWldtm9lk6zuuccy59Lju6MO4QkpLqQN0zgDsIlttYBfQG5gEHpB6ac865dDrpwB5xh5CUVMdB3QYMARaY2d4E3b7/k3JUTdidkxfEHYJzLkd9+dU2vvwqe2aHSzVBlZrZF0AzSc3M7HVgUOphNV2JY6Scc64xfffxaXz38WlxhxFZqs+g1kpqD7xJMDZpFcF8ec455zLMVV/bJ+4QkqLkptGrVllqB2wh6F5+IdAJeCK8q8oYRUVFVlxcHNv3V59dopLPLuGcyxWSpplZUmNYU0pQ2SLuBJXIZ5dwzsVl1YYtAHTr0LqOI9OvPgmqvgN1axygiw/Udc65jPW9v34INPFxUD5At/5qml3C141yzjWG7w7tE3cISUl5oK6kQ4FjCO6g3jKzD1OOqgmrKRH5ulHOucYwtF+3uENISkrdzCX9HBgH7EGw9Majkn6WjsCcc86lV8nazZSs3Rx3GJGl2otvHnCImW0Jt9sAH5jZ/mmKLy0yqZNEJe/Z55xrbOfd/w4QzzOoRuskkWAxwRx8W8LtVsAndVWSdBJwN8F6UA+a2e3V9ivcfwrBelCXmtkHCfvzgGJguZmdluI1xMLXjXLONbbvfSO7VlhINUFtBeZImkzwDGoY8JakPwGY2ferVwiTy73hscuAqZLGm1niyrgnA33D1xHAfeF7pesI5vzz3oLOORfRMX27xB1CUlJNUM+Hr0pvRKgzGFhoZosAwmXdh7Pj0u3DgcfChQvfldRZUg8zWyGpADgV+BXwwxTjzwi+bpRzrjF89sUmAPbao23MkUSTaoJ6xcxWJRZI6mdm82upkw8sTdhexo53R7s6Jh9YAdwF/ASotau7pJHASIC99tqrtkNj58+cnHON4X+fnQFkzzioVCeL/bekcys3JP2IHe+oaqIayqr31KjxGEmnAavMrM7ZDs1srJkVmVlR165d6zo84/is5865dEt89p0NUk1QQ4GLJf1N0pvAfgRNeLVZBvRK2C4ASiIeczRwhqTFwFPANyQ9Xu/oM5jPeu6cS7ch++zBkH32iDuMyFJKUGa2ApgIHAkUEjw32lhHtalAX0l7S2oJjADGVztmPPAdBYYA68xshZndaGYFZlYY1vunmV2UyjU451yu+GT1Rj5ZXdev6MyR6oq6kwmeCx1IcJfzsKQ3zezHu6pjZmWSrgVeJehm/rCZzZE0Ktw/BphA0MV8IUE388tSiTNbVB8bVTj6ZWD72CifEsk5l4qbnpsFZM8zqFQH6n7LzP6RsJ0H3GRmt6UhtrTJxIG6dalpbJSPl3LOpWLaki8BOKz37o3+3Y0+UNfM/iHpGKCvmT0C7AY0yWdCzjmX7eJITKlItYnvZqAI6Ac8ArQkSFBHpx5abqscG+XNfs65dJn/+QYA+u2ZHQtSpNrENx04hGD+vUPCsplmdlB6wkuPbGziq4k3+znnUpFrc/FtMzOTZGEA7VI8n3POuQZy0ykZNY93nVJNUM9Iuh/oLOkq4HLggdTDcjWJ2uznnHM1ObhX57hDSEpKTXwAkoYBJxDM/vCqmU1OR2Dp1FSa+GriTXzOuajmlKwD4ICenRr9u+No4iNMSBmXlJxzzu3oFy8Gc3JnyziolBOUi5fPhO6ci+rnpw+IO4SkeILKcv7MyTkXVRxNe6lIdbLYHUjqJel/03lOlzyfCd05V5MZS9cyY+nauMOILOUEJamLpO+Gs5m/AXRPOSqXkppmQvek5Zz79YR5/HrCvLjDiKxeTXySOgBnAhcQLLHxPLCPmRWkMTaXRndP+dibA53Lcb8YfmDcISSlvs+gVgHvAz8D3goH656ZvrBcsnxslHOuLtkyxVGleo2DkvQDgvWY2gF/BZ4GJpvZPhHrnwTcTbDcxoNmdnu1/Qr3n0Kw3MalZvaBpF7AY8CeQAUw1szuruv7mvI4qJpUjo2qnrQqedJyLjflxGzmZnYncKekfYDzgX8APSXdADxvZrt84BEuyXEvMIxg5dypksab2dyEw04G+oavI4D7wvcy4EdhsuoATJM0uVpdF0pc3tkH9DrnfjdxPpA946BSXVF3kZn9yswGAocDnYBX6qg2GFgY1t1GsHT78GrHDCdYndfM7F2CqZR6hKvqfhB+9wZgHpCfyjU0RVHHRnnHCedyy6/PGsivzxoYdxiR1StBSdpX0g5LapjZLILl30+so3o+sDRhexk7J5k6j5FUSDCT+nu7iHGkpGJJxatXr64jpKalpua7mpKW9/ZzLrf06dqePl3bxx1GZPW9g7oL2FBD+Sbgzjrqqoay6g/Caj1GUnvg78D1Zra+pi8xs7FmVmRmRV27dq0jpKYv6jOnmpKWc65peHfRF7y76Iu4w4isvr34Cs1sZvVCMysO72xqswzolbBdAJREPUZSC4Lk9ISZPZdk3DnPe/s5l7sqW0iy5RlUfXvxLTSzfZPdF+5vDiwAjgeWA1OBC8xsTsIxpwLXEvTiOwL4k5kNDnv3jQO+NLPro8aba734oora289X7XWuafjsi00A7LVH20b/7saczXyqpKvMbIe1nyRdAUyrraKZlUm6FniVoJv5w2Y2R9KocP8YYAJBclpI0Gx4WVj9aOBiYFa4mi/ATWY2oZ7X4ai7t19Ng3w9aTmXfeJITKmob4K6Hnhe0oVsT0hFQEuCGSZqFSaUCdXKxiR8NuCaGuq9Rc3Pp1w9pDITuict57LPWx+vAeCYvl1ijiSa+o6DWgkcJenrQOXcGS+b2T/TFplrcLX19qvPsypPWs5ltj//M/g3nS0Jqr7PoFoDo4B9gVnAQ2ZWlubY0safQaUm6rOqmpoHfYCwc5mjZO1mAHp2btPo312fZ1D17WY+jqBJbxbBrA9/qOd5XBb5wbD9WHz7qVUJZ/Htp3Ld8X25e8rHVXdYhaNfpnD0y7WOp/KxVs7Fo2fnNrEkp/qqb4IaYGYXmdn9wNnAsWmMyWWY2p5V1Sdp+QBh5+LxxvxVvDF/VdxhRFbfThKllR/CXnlpCsdloqgzUyQen+wcgP78yrmGd98bnwAwtF+3mCOJpr53UAdLWh++NgAHVX6WVOPMDq5pSTZp3Tl5QdWdFERrCox6pxW1zLlc9+cLDuHPFxwSdxiR1StBmVmemXUMXx3MrHnC547pDtJlh9qSVrqeX9WUtKKWedJyua5bh9Z069A67jAiS3nJd+dqU1sTXbqSVlSp3JE51xS8Nnclr81dGXcYkdX3GZRz9Zbs86vK7u2VCaYyeSWqrSzZsVtRn4f5MzKXbR749yIAvjmge8yRROMJyjW6dHe6qK1sV8kt2clxPZG5puC+iw6LO4SkeBOfywjJJq1kzhu1GTHZThw1SeV5WLrLnKtu93Yt2b1dy7jDiMwTlMtYUZNW1LLE81ZPWomvyrJMSGTp7hTiSTC3TZy9gomzV8QdRmSeoFxWqSlpRS1L9o4sExJZKjIlCXpSzByP/Gcxj/xncdxhRBZLgpJ0kqT5khZKGl3Dfkn6U7h/pqRDo9Z1bldSuSOr67zpTmSplGVaEszGO8OmWvbAJUUcslfnnY7LVI3eSUJSHnAvMIxg5dypksab2dyEw04G+oavI4D7gCMi1nUuslTuvuqTyOrb2SNqWao9HqOWxbkCc9QOK162c1nH1i0Y869FjD55f7JBHL34BgMLzWwRgKSngOFAYpIZDjwWrgv1rqTOknoAhRHqOpd2jZnIUpGpSTDbk2JT8eKMkrhDSEq9lttI6Quls4GTzOzKcPti4AgzuzbhmJeA28MFCpE0BbiBIEHVWjfhHCOBkQB77bXXYUuWLGnQ63IuGVG7o6dS1lAJKtmydCZFl16NmfTrs9wGZtaoL+Ac4MGE7YuBP1c75mXgmITtKcBhUerW9DrssMPMuVzzx0nzG7ys9w0v1VkW5Rgva5yyTVvLajyuMQDFlmS+iKOJbxnQK2G7AKh+37mrY1pGqOucI7Uej+ls0kxlaEBjNo/mgjYt8+IOISlx9OKbCvSVtLeklsAIYHy1Y8YD3wl78w0B1pnZioh1nXONJEoiiyMpelnNZc9/uIwTs2SaI4jhGRSApFOAu4A84GEz+5WkUQBmNkbBAlP3ACcBm4DLzKx4V3Xr+j5f8t055+C8+98B4Omrj2z0767PM6hYElRj8wTlnHNQWl4BQIu8xm88q0+C8slinXMuR8SRmFKRXdE655yrt78VL+VvxUvjDiMyT1DOOZcjnp22jGenLYs7jMhy4hmUpNVA9ZG6XYA1MYSTbn4dmcWvI3M0hWuApnMd/cysQzIVcuIZlJl1rV4mqTjZB3aZyK8js/h1ZI6mcA3QtK4j2TrexOeccy4jeYJyzjmXkXI5QY2NO4A08evILH4dmaMpXAPk8HXkRCcJ55xz2SeX76Ccc85lME9QzjnnMpInKOeccxnJE5RzzrmM5AnKOedcRvIE5ZxzLiN5gnLOOZeRPEE555zLSDkxWWyXLl2ssLAw7jCccy5nTZs2bU1NE3fXJicSVGFhIb7ku3POxUdS9SWP6uRNfM455zKSJyjnnHMZyROUc865jOQJyjnnXEbyBOWccy4jeYJyzjmXkTxBOedcjjjv/nc47/534g4jMk9QzjnnMpInKOeccxmpQROUpJMkzZe0UNLoGvbvJul5STMlvS/pwIR9iyXNkjRdUnFC+e6SJkv6OHzfrSGvwTnnXDwaLEFJygPuBU4GBgDnSxpQ7bCbgOlmdhDwHeDuavu/bmaDzKwooWw0MMXM+gJTwm3nYpdt7ftx8Z+Ti6oh76AGAwvNbJGZbQOeAoZXO2YAQZLBzD4CCiV1r+O8w4Fx4edxwLfSFrFzzrmM0ZAJKh9YmrC9LCxLNAM4C0DSYKA3UBDuM2CSpGmSRibU6W5mKwDC9241fbmkkZKKJRWvXr065YtxzjnXuBoyQamGMqu2fTuwm6TpwPeAD4GycN/RZnYoQRPhNZKOTebLzWysmRWZWVHXrknN8O6ccy4DNORyG8uAXgnbBUBJ4gFmth64DECSgE/DF2ZWEr6vkvQ8QZPhm8BKST3MbIWkHsCqBrwG55xzMWnIO6ipQF9Je0tqCYwAxiceIKlzuA/gSuBNM1svqZ2kDuEx7YATgNnhceOBS8LPlwAvNOA1OOeci0mD3UGZWZmka4FXgTzgYTObI2lUuH8MsD/wmKRyYC5wRVi9O/B8cFNFc+CvZjYx3Hc78IykK4DPgHMa6hqcc87Fp0FX1DWzCcCEamVjEj6/A/Stod4i4OBdnPML4Pj0Ruqccy7T+EwSzjnnMpInKOeccxnJE5RzzrmMVOszKEmtgdOArwE9gc0EveleNrM5DR+ec865XLXLBCXpFuB04A3gPYLxRq2B/YDbw+T1IzOb2fBhOuecyzW13UFNNbNbdrHvj5K6AXulPyTnnHOulgRlZi/XVtHMVuGzODR5lbNOP331kTFH4pzLNbU18b3IznPnVTGzMxokIuecc47am/j+0GhROOecc9XU1sT3r8YMxDnnnEtU51RHkvoCvyFYXLB1ZbmZ7dOAcTnnnMtxUQbqPgLcR7BO09eBx4C/NGRQzjnnXJQE1cbMpgAysyVh1/NvNGxYzjnncl2U2cy3SGoGfBwun7GcXSyz7pxzzqVLlDuo64G2wPeBw4CL2L5goHPOOdcgotxBlZnZRmAj4fLszjnnXEOLcgf1R0kfSbpN0gHJnFzSSZLmS1ooaXQN+3eT9LykmZLel3RgWN5L0uuS5kmaI+m6hDq3SFouaXr4OiWZmJxzzmWHOhOUmX0dGAqsBsZKmiXpZ3XVk5QH3AucTNBF/XxJA6oddhMw3cwOAr4D3B2WlxFMRLs/MAS4plrdO81sUPiagHPOuVqVVxjlFUZpeQVmu5wkKKNEWvLdzD4H/iTpdeAnwM+BX9ZRbTCwMFy+HUlPAcOBuQnHDCAYY4WZfSSpUFJ3M1sBrAjLN0iaB+RXq+ucc1mrtLyCLaXlbCkN3reWbf9c9R6WbS4tZ2tpeY37Ksu2lpWzeVsN5eGxpeXbk9K28gpaNc+L8eqjiTJQd3/gPOBs4AvgKeBHEc6dDyxN2F4GHFHtmBnAWcBbkgYDvYECYGXC9xcChxAs+VHpWknfAYoJ7rT+GyEe55yrkZlRWm7hL/dytiYmispf/KXlbCkLk0ktiWJLZSIpq7YdJpHKsrKK+t3FSNCmRR6tW+TRunkzWrfIo1WLPFq3aEbr5nl0aN082FdZVnVsHs9OW0qzZkIozT/BhhHlDuoR4EngBDMrSeLcNf0Eqv+J3A7cLWk6MAv4kKB5LziB1B74O3C9ma0Pi+8DbgvPdRtwB3D5Tl8ujQRGAuy1l68K4lw2MTO2lVdU3QFs3umX//bPW8MkUpkENicmhF0kii1l5WzZtuN56pkvyGumqkQRJIsgUVQmh85tWmwvDxPF9sSxvaxVi2bbE0+1fa1bNKtKQi3zmiHVL8G8/ckaAFo2z47F1OtMUGY2pJ7nXgb0StguAHZIcGHSuQxAwU/80/CFpBYEyekJM3suoU7i3dUDwEu7iHssMBagqKgoOxpcnctgZsbWsoodEkFVk1L4vnlbYoLYvn/ztu1JYcHKDZjB+WPfrTp2a9nOCaS+j0maN1PVL/hWzfNo03L73UXbls3ZvV34y756ogiPbZVwZ1JToqhe3iIvO37ZZ6O6ltsYC0w0s9Jq+/YBLgUWm9nDuzjFVKCvpL0JBveOAC6odp7OwCYz2wZcCbxpZuvDZPUQMM/M/litTo/wGRXAmQRL0DuXs0rLE5LCtu1NUomJouaEUpHUcfVNGnnNFN4ZBL/Qt5RW0ExQVlFBh9bN6dK+VdW+NtWapVpVTxTNa2i62qEZqxnNPWE0GbXdQV0F/BC4S9KXBL34WgOFwCfAPWb2wq4qm1lZOPPEq0Ae8LCZzZE0Ktw/BtgfeExSOUEHiCvC6kcDFwOzwuY/gJvCHnu/kzSIoIlvMXB1ktfsXIOrqLDtzy4qf8FX3lUkNkVV3WFUb57anjg2l1bseFzlHUm4v77PMiqTQWKzUuXdxm5tW9AqTBiJx1WVtayhrPIclUmjZfC5+h2GL4LpoqptuY3PCXrs/STsqNAD2AwsMLNNUU4eJpQJ1crGJHx+B+hbQ723qPkZFmZ2cZTvdq6hfbFxK7OWr2PWsnXMXL6O6UvXUlZh7PezV9hWVlGvc7bMaxb84m+5/Zd9kACasUe7lrTunFctUezYNBUloVTemdT3OYZzjSVqN/PFBHcrzuWkdZtKmbV8HTOXrw0S0rJ1LF+7uWr/Pl3a0b5Vc5rniW8dkr/THUXlA/DExLNjs1bwymvmScO5SpESlHO5ZP2WUmYn3BnNWraOz77c3mjQe4+2HLJXZ75zZG8GFnTiwPxOdGzdoqrp6saT948rdOeaFE9QLqdt3FrGnOXrgqa6MBktWvNV1f78zm04qKATIwb34qD8zhyY35HObVvGGLFzuSPKQN3TgAlmVr9GdecyxOZt5cxdETTPVd4dfbJ6Y1XPtB6dWjMwvxNnHZrPwILODMzvxO7tPBk5F5cod1AjCAbT/h14xMzmNXBMzqVsS2k581asD54bhQnp41UbqgZjdu3QioMLOnHaQT04KGym69ahdbxBO+d2EGWg7kWSOgLnA49IMsLZJcxsQ0MH6FxdtpaVs+DzjTt0YFiwckNV9+s92rVkYEEnTjygOwMLOnNQQSe6d/Rk5Fymi9qLb314B9WGYAHDM4H/lfQnM/tzA8bn3A5KyytYsHLDDh0YPvp8fdVEmJ3btmBgfieu7r8PA/M7M7CgEz07tfYu1c5loSjPoE4nmOuuD/AXYLCZrZLUFpgHeIJyDaKsvIKFqzcyc9k6ZodNdXNXrK8aY9ShdXMG5nfi8mP25qD84M6oYLc2noycayKi3EGdQ7D+0puJhWa2SdJOk7Q6Vx/lFcana4JkNHNZ0KNuTsk6tpQGyahdyzwOzO/EJUf2Dprp8jux1+5taebjhpxrsqIkqJsJ12YCkNQG6G5mi81sSoNF5pqsigpj8Rdf7dCBYU7JOr7aVg4EU/AcmN+RCwb3ZmBBRwbmd2afLu08GTmXY6IkqL8BRyVsl4dlhzdIRK5JMTM++3LT9imBwua6DVuDVVVaNW/GgJ4dOfuwgqoODH26tvcZFZxzkRJU83C2cQDMbJskHxzidmJmLF+7eYcODLOWr2Pd5mAy/JZ5zdi/RweGH9KTg8IODPt2a+/LFTjnahQlQa2WdIaZjQeQNBxY07BhuUxnZny+fssOHRhmLV/Hl18F/5dp3kz079GBUwb2YGB+Jw4q6MR+3TtkzUJpzrn4RUlQo4AnJN1DMMP4UuA7DRqVyzirNmypaqKrfHa0ZuNWIFjvp2+39nxz/25VHRj67dmB1i3yYo7aOZfNogzU/QQYEi6/Lh+cmzsqKozFa77iy03bGPyroD9MM8G+3dpz3H5dOaigEwMLOjGgR0dPRs65tIs0UFfSqcABQOvKMSZm9osGjMtlgKemLmXlhq3s1rYF136jLweFyahdK59j2DnX8KIM1B0DtAW+DjwInA2838BxuZit2rCF37wyj46tm9O3W3uuOGbvuENyzuWYKE+sjzKz7wD/NbNbgSOBXlFOLukkSfMlLZQ0uob9u0l6XtJMSe9LOrCuupJ2lzRZ0sfh+25RYnHJue2leWwtraCwSzufmcE5F4soCWpL+L5JUk+gFKjzv9OS8oB7gZOBAcD5kgZUO+wmYLqZHUTQ8eLuCHVHA1PMrC8wJdx2afTG/FW8OKOEa76+L2382ZJzLiZREtSLkjoDvwc+IFj6/ckI9QYDC81sUTiO6ilgeLVjBhAkGczsI6BQUvc66g4HxoWfxwHfihCLi2jztnL+74XZ9OnajlFD94k7HOdcDqs1QUlqRnC3stbM/g70Bvqb2c8jnDufoEt6pWVhWaIZwFnhdw0Oz19QR93uZrYCIHzvtovYR0oqllS8evXqCOE6gD/982OWfrmZX585kFbN/e7JORefWhNUuIruHQnbW81sXcRz1/Tgwqpt3w7sJmk68D3gQ6AsYt1amdlYMysys6KuXbsmUzVnffT5eh54cxHnFhVwxD57xB2Ocy7HRekvPEnSt4HnzCyZJLGMHTtTFAAliQeY2XrgMgAFT+I/DV9ta6m7UlIPM1shqQewKomY3C5UVBg3PjeLjm1acOPJ+8cdjnPORXoG9UOCyWG3SlovaYOk9RHqTQX6Sto7nLtvBDA+8QBJnRPm9bsSeDNMWrXVHQ9cEn6+BHghQiyuDn99/zM+/GwtPzt1f3Zr51MtOufiF2UmiQ71ObGZlUm6FngVyAMeNrM5kkaF+8cA+wOPSSoH5gJX1FY3PPXtwDOSrgA+I1ivyqVg1fot/HbiRxy97x6ceUj1x4TOuabi6auPjDuEpEQZqHtsTeXVFzDcxTETgAnVysYkfH4H6Bu1blj+BXB8Xd/tovvFS3PZWlbBL7810Mc8OecyRpRnUP+b8Lk1QRfwacA3GiQi16hen7+Kl2au4EfD9mPvLu3iDsc556pEaeI7PXFbUi/gdw0WkWs0m7aV8bPnZ7Nvt/aMPM7HPLnGkW3NTC4+9Zn1cxlwYJ1HuYx395SPWb52M89cfaSPeXLOZZwoz6D+zPYxSM2AQQQDbF0Wm7diPQ/++1NGHN6LwXvvHnc4zjm3kyh3UMUJn8uAJ83sPw0Uj2sE5eGYp85tWjD65P5xh+OcczWKkqCeBbaYWTkEE7lKamtmmxo2NNdQ/vreEqYvXctd5w2ic1sf8+Scy0xRBupOAdokbLcBXmuYcFxDW7l+C7+bOJ9j9u3C8EE94w7HOed2KcodVGsz21i5YWYbJbVtwJhcA/rFi3PZVl7BL791oI95SjPvneZcekW5g/pK0qGVG5IOAzY3XEiuofzzo5W8PGsF3z++L4U+5sk5l+Gi3EFdD/xNUuVkrT2A8xosItcgNm0r4//+MYe+3dpz1dd8zJNzLvNFGag7VVJ/oB/BMhgfmVlpg0fm0uqu14IxT38bdSQtm0e5cXbOuXjV+ZtK0jVAOzObbWazgPaS/qfhQ3PpMqdkHQ+99SnnD+7F4YU+5sk5lx2i/Ff6KjNbW7lhZv8FrmqwiFxalVcYNz0/m93atmD0Sb7Ok3Mue0RJUM2U0N1LUh7gg2eyxBPvLWHG0rX832kD6NS2RdzhOOdcZFE6SbxKsP7SGIIpj0YBExs0KpcWn68Lxjx9rW8XzjjYxzw557JLlAR1A3A18F2CThKTgAcbMiiXHre+OIdSH/PknMtSdTbxmVmFmd1nZmeb2bfN7P7KaY/qIukkSfMlLZQ0uob9nSS9KGmGpDmSLgvL+0manvBaL+n6cN8tkpYn7DslyWvOCa/NXckrsz/n+8f3pfcePubJOZd9osxm3hf4DTCAYMFCAMys1sE04bOqe4FhBEt0TJU03szmJhx2DTDXzE6X1BWYL+kJM5tPMGt65XmWA88n1LvTzP4Q4fpy0ldby7h5/Bz26+5jnpxz2StKJ4lHgPsIZjL/OvAY8JcI9QYDC81skZltA54Chlc7xoAOYSeM9sCX4fckOh74xMyWRPhOB9z12gKWr93Mb84a6GOenHNZK8pvrzZmNgWQmS0xs1uIttx7PrA0YXtZWJboHmB/oASYBVxnZhXVjhkBPFmt7FpJMyU9LGm3mr5c0khJxZKKV69eHSHcpmH28nU8/J/FXHDEXhzW28c8OeeyV5QEtUVSM+BjSddKOhPoFqFeTU/lrdr2icB0oCdBk949kjpWnUBqCZwB/C2hzn1An/D4FcAdNX25mY01syIzK+ratWuEcLNfMOZpFru1bckNJ/o6T8657BYlQV0PtAW+DxwGXARcEqHeMqBXwnYBwZ1SosuA5yywEPgUSPzNejLwgZmtrCwws5VmVh7eaT1A0JTogL+8s5iZy9bx89N9zJNzLvtFmosv/LiRIKFENRXoK2lvgk4OI4ALqh3zGcEzpn9L6k4w39+ihP3nU615T1IPM1sRbp4JzE4ipiZrxbrN/GHSAo7dryunH9Qj7nCccy5lUcZB1YuZlUm6lmCgbx7wsJnNkTQq3D8GuA14VNIsgibBG8xsDUC45tQwgjFYiX4naRBBc+HiGvbnpFvHz6WsooJfpXnMk69x5JyLS4MlKAAzmwBMqFY2JuFzCXDCLupuAvaoofziNIeZ9SbPXcnEOZ9zw0n96bW7ryXpnGsavA9yltu4tYyfvzCbft07cOXX9o47HOecS5soA3W7EsxeXph4vJld3nBhuajunLyAz9dv4Z4LDqVFnv9/wznXdERp4nsB+DfwGhBpiiPXOGYvX8cj//mUC4/Yi8N61zgczDnnslaUBNXWzG5o8EhcUsorjBufm8Ue7Vvxvz7myTnXBEVpE3rJJ2TNPOPeXsys5eu4+fQBdGrjY56cc01PlAR1HUGS2iJpQ/ha39CBuV0rWbuZOybNZ2i/rpw60Mc8OeeapigDdTs0RiAuulvGz6HcjNuG+zpPzrmmK9I4KElnAMeGm2+Y2UsNF5KrzatzPmfS3JXceLKPeXLONW11NvFJup2gmW9u+LouLHONbOPWMm4ZP4f+e3bg8mN8zJNzrmmLcgd1CjCochkMSeOAD4GdVsh12513/ztAeqcKumPSfD5fv4V7L/QxT865pi/qb7nOCZ87NUAcrg4zl61l3NuLueiI3hy6l495cs41fVHuoH4DfCjpdYIJXY8FbmzQqNwOysoruOn5WXRp34r/Palf3OE451yjiNKL70lJbwCHs33G8c8bOjC33bh3ljB7+Xr+34WH0rG1j3lyzuWGXTbxSeofvh8K9CBYgHAp0DMsc41geTjm6Rv9u3HygXvGHY5zzjWa2u6gfgiMpOYl1Q34RoNE5KqYGTe/MBszuPWMA3zMk3Mup+wyQZnZyPDjyWa2JXGfpNYNGpUD4NU5K3lt3ipuOsXHPDnnck+UXnxvRyzbiaSTJM2XtFDSTt3SJXWS9KKkGZLmSLosYd9iSbMkTZdUnFC+u6TJkj4O35tkl7YNW0q5Zfwc9u/RkcuO9jFPzrncU9szqD0lHQa0kXSIpEPD11Cgzv/OS8oD7gVOBgYA50saUO2wa4C5ZnYwMBS4Q1LLhP1fN7NBZlaUUDYamGJmfYEpNNHxWHdMWsDKDVv4zVkDfcyTcy4n1fYM6kTgUqAA+GNC+QbgpgjnHgwsNLNFAJKeAoYTzEZRyYAOCh6utAe+BMrqOO9wgmQGMA54A2hSy4HMWLqWce8s5jtDejOoV+e4w3HOuVjU9gxqHDBO0rfN7O/1OHc+Qa+/SsuAI6odcw8wHigBOgDnVc5YQZC8Jkky4H4zGxuWdzezFWGMKyR1q+nLJY0k6OTBXnvtVY/w41FWXsGNz82iW4dW/OhEH/PknMtdUcZB/V3SqcABQOuE8l/UUbWmLmdWbftEYDpBj8A+wGRJ/zaz9cDRZlYSJqDJkj4yszfrijchvrHAWICioqLq35uxHn17MXNXrOc+H/PknMtxUSaLHQOcB3yPIOmcA/SOcO5lQK+E7QKCO6VElwHPWWAh8CnQH8DMSsL3VcDzBE2GACsl9Qhj6wGsihBLVlj2303cMWkBx/fvxkk+5sk5l+OiPH0/ysy+A/zXzG4FjmTHxLMrU4G+kvYOOz6MIGjOS/QZcDyApO5AP2CRpHaSOoTl7YATgNlhnfHAJeHnS4AXIsSS8YIxT3OQ4Bff8nWenHMuylx8m8P3TZJ6Al8AdfZ7NrMySdcCrwJ5wMNmNkfSqHD/GOA24FFJs9g+jdIaSfsAz4e/pJsDfzWzieGpbweekXQFQYI7J+K1ZrSJsz9nyker+Nmp+5PfuU3c4TjnXOyiJKiXJHUGfg98QPAc6cEoJzezCcCEamVjEj6XENwdVa+3CDh4F+f8gvCuq6lYv6WUm8fPYUCPjlx6VGHc4TjnXEaI0knitvDj3yW9BLQ2s3UNG1ZuuePV+azeuJUHvlNEcx/z5JxzQLROEteEd1CY2VagmaT/aejAcsX0pWt57N0lXHJkIQf7mCfnnKsS5b/rV5nZ2soNM/svcFWDRZRDKsc8de/Qmh+dsF/c4TjnXEaJkqCaKaFLWTiFUctajncRPfyfT5m3Yj23nHEAHXzMk3PO7SBKJ4lXCXrNjSHoIDEKmFh7FVeXpV9u4s7JH/PN/btz4gHd4w7HOecyTpQEdQNwNfBdgq7gk4jYi8/VzMz4+QuzkeDW4b7Ok3PO1SRKL74K4L7w5dLgldmf8/r81T7myTnnarHLBCXpGTM7NxxEu9NcdmZ2UING1kStD9d5OjDfxzw551xtaruDuj58P60R4sgZv584nzUbt/LQJYf7mCfnnKtFbQnqJeBQ4JdmdnEjxdOkffDZf3n8vSVcelQhAws6xR2Oc85ltNoSVEtJlwBHSTqr+k4ze67hwmp6SssruKlqzJOv8+Scc3WpLUGNAi4EOgOnV9tngCeoJDz81qd89PkG7r/4MNq3itJ50jnnclttK+q+BbwlqdjMHmrEmJqcpV9u4s7XFnDCgO6ceICv8+Scc1HU1ovvG2b2T+C/3sRXf2bGz/4xmzyJW844IO5wnHMua9TW1nQc8E92bt4Db+KL7OVZK/jXgtX8/LQB9PQxT845F1ltTXw3h++XNV44TUtZeQW3vjiXgfmduMTHPDnnXFKiLLdxnaSOCjwo6QNJOy0yuIu6J0maL2mhpNE17O8k6UVJMyTNkXRZWN5L0uuS5oXl1yXUuUXScknTw9cpyVxwY1r63818sXErvzlrIHnNfDoj55xLRpSRopeb2XqClW+7AZcRLLteq3DW83uBk4EBwPmSBlQ77BpgrpkdDAwF7pDUEigDfmRm+wNDgGuq1b3TzAaFrwlkoA1bSlm1YSuXHb03B+b7mCfnnEtWlARV+V//U4BHzGxGQlltBgMLzWyRmW0DngKGVzvGgA7hch7tgS+BMjNbYWYfAJjZBmAekB/hOzNCaXkFn67ZRMu8ZvxwmK/z5Jxz9RElQU2TNIkgQb0qqQNQEaFePrA0YXsZOyeZe4D9gRJgFnBdODltFUmFwCHAewnF10qaKelhSbtFiKVR5Uns2bEVe3dpSzsf8+Scc/USJUFdAYwGDjezTUALgma+utR0l1V90tkTgelAT2AQcI+kjlUnkNoDfweuD5sZIZhVvU94/Argjhq/XBopqVhS8erVqyOEmz7NmoluHVvTua2v6+icc/UVJUEdCcw3s7WSLgJ+BqyLUG8Z0Cthu4DgTinRZcBzFlgIfAr0B5DUgiA5PZE45srMVppZeXin9QBBU+JOzGysmRWZWVHXrl0jhOuccy6TRElQ9wGbJB0M/ARYAjwWod5UoK+kvcOODyOA8dWO+Qw4HkBSd6AfsCh8JvUQMM/M/phYQVKPhM0zgdkRYnHOOZdlojwgKTMzkzQcuNvMHgonka2VmZVJupZgyfg84GEzmyNpVLh/DHAb8Gi45pSAG8xsjaRjgIuBWZKmh6e8Keyx9ztJgwiaCxcTrPbrnHOuiYmSoDZIuhG4CDg27D7eIsrJw4QyoVrZmITPJQTd16vXe4td9BT0pT+ccy43RGniOw/YClxhZp8T9MT7fYNG5ZxzLufVeQcVJqU/Jmx/RrRnUM4551y9RZnqaIikqZI2StomqVxSlF58zjnnXL1FaeK7Bzgf+BhoA1xJMIWRc84512AiTXNgZgsl5ZlZOfCIpLcbOC7nnHM5LkqC2hSOY5ou6XcEsze0a9iwnHPO5booTXwXE4xjuhb4imB2iG83ZFDOOedclF58S8KPm4FbGzYc55xzLrDLBBXO7lB9ctcqZnZQg0TknHPOUfsd1GmNFoVzzjlXTW0JqgXQ3cz+k1go6WvsPCu5c845l1a1dZK4C9hQQ/nmcJ9zzjnXYGpLUIVmNrN6oZkVA4UNFpFzzjlH7QmqdS372qQ7EOeccy5RbQlqqqSrqhdKugKY1nAhOeecc7V3krgeeF7ShWxPSEVAS4KVbJ1zzrkGs8sEZWYrgaMkfR04MCx+2cz+2SiROeecy2l1TnVkZq+b2Z/DV1LJSdJJkuZLWihpdA37O0l6UdIMSXMkXVZXXUm7S5os6ePwfbdkYnLOOZcdoszFVy/h0vD3AicDA4DzJQ2odtg1wFwzOxgYCtwhqWUddUcDU8ysLzAl3HbOOdfENFiCAgYDC81skZltA54Chlc7xoAOkgS0B74EyuqoOxwYF34eB3yrAa/BOedcTBoyQeUDSxO2l4Vlie4B9ieYmWIWcJ2ZVdRRt7uZrQAI37vV9OWSRkoqllS8evXqVK/FOedcI2vIBKUayqpPPnsiMB3oCQwC7pHUMWLdWpnZWDMrMrOirl27JlPVOedcBmjIBLWMYO2oSgXsPIffZcBzFlgIfAr0r6PuSkk9AML3VQ0Qu3POuZg1ZIKaCvSVtHe4Iu8IYHy1Yz4DjgeQ1B3oByyqo+544JLw8yXACw14Dc4552ISZcn3ejGzMknXAq8SrMj7sJnNkTQq3D8GuA14NFx7SsANZrYGoKa64alvB54JZ7T4DDinoa7BOedcfBosQQGY2QRgQrWyMQmfS4ATotYNy78gvOtyzjnXdDVkE59zzjlXb56gnHPOZaQGbeLLZU9ffWTcITjnXFbzOyjnnHMZyROUc865jOQJyjnnXEbyBOWccy4jeYJyzjmXkTxBOeecy0ieoJxzzmUkmSW1ikVWkrQaWFKtuAuwJoZw0s2vI7P4dWSOpnAN0HSuo5+ZdUimQk4M1DWznRaEklRsZkVxxJNOfh2Zxa8jczSFa4CmdR3J1vEmPueccxnJE5RzzrmMlMsJamzcAaSJX0dm8evIHE3hGiCHryMnOkk455zLPrl8B+Wccy6DeYJyzjmXkXIuQUk6SdJ8SQsljY47nmRIeljSKkmzE8p2lzRZ0sfh+25xxlgXSb0kvS5pnqQ5kq4Ly7PtOlpLel/SjPA6bg3Ls+o6KknKk/ShpJfC7ay7DkmLJc2SNL2yS3OWXkdnSc9K+ij8d3Jktl2HpH7hn0Pla72k65O9jpxKUJLygHuBk4EBwPmSBsQbVVIeBU6qVjYamGJmfYEp4XYmKwN+ZGb7A0OAa8I/g2y7jq3AN8zsYGAQcJKkIWTfdVS6DpiXsJ2t1/F1MxuUMG4oG6/jbmCimfUHDib4c8mq6zCz+eGfwyDgMGAT8DzJXoeZ5cwLOBJ4NWH7RuDGuONK8hoKgdkJ2/OBHuHnHsD8uGNM8npeAIZl83UAbYEPgCOy8TqAgvCXxTeAl8KybLyOxUCXamVZdR1AR+BTwg5s2Xod1WI/AfhPfa4jp+6ggHxgacL2srAsm3U3sxUA4Xu3mOOJTFIhcAjwHll4HWGz2HRgFTDZzLLyOoC7gJ8AFQll2XgdBkySNE3SyLAs265jH2A18EjY5PqgpHZk33UkGgE8GX5O6jpyLUGphjLvZx8DSe2BvwPXm9n6uOOpDzMrt6AJowAYLOnAmENKmqTTgFVmNi3uWNLgaDM7lKAJ/xpJx8YdUD00Bw4F7jOzQ4CvyPDmvNpIagmcAfytPvVzLUEtA3olbBcAJTHFki4rJfUACN9XxRxPnSS1IEhOT5jZc2Fx1l1HJTNbC7xB8Hww267jaOAMSYuBp4BvSHqc7LsOzKwkfF9F8LxjMNl3HcuAZeHdOMCzBAkr266j0snAB2a2MtxO6jpyLUFNBfpK2jvM7COA8THHlKrxwCXh50sInulkLEkCHgLmmdkfE3Zl23V0ldQ5/NwG+CbwEVl2HWZ2o5kVmFkhwb+Hf5rZRWTZdUhqJ6lD5WeC5x6zybLrMLPPgaWS+oVFxwNzybLrSHA+25v3INnriPsBWgwP7E4BFgCfAD+NO54kY38SWAGUEvxP6wpgD4IH3B+H77vHHWcd13AMQbPqTGB6+DolC6/jIODD8DpmAz8Py7PqOqpd01C2d5LIqusgeHYzI3zNqfy3nW3XEcY8CCgO/279A9gtS6+jLfAF0CmhLKnr8KmOnHPOZaRca+JzzjmXJTxBOeecy0ieoJxzzmUkT1DOOecykico55xzGckTlHNuJ5KGSjoq7jhcbvME5ZyryVDAE5SLlSco53ZBUmG4Hs8D4ZpPk8JZI2o6dl9Jr4XrQ30gqY8Cv5c0O1yn6Lzw2KGS/iXpGUkLJN0u6cJwfalZkvqExz0qaYykf4fHnRaWt5b0SHjsh5K+HpZfKuk5SRPD9XZ+lxDfCZLeCWP7WzgXYuUaSreG5bMk9Q8n8R0F/CBcy+drks4Jr2OGpDcb9AfvXKh53AE4l+H6Aueb2VWSngG+DTxew3FPALeb2fOSWhP85+8sglkBDga6AFMTfrkfDOwPfAksAh40s8EKFnD8HnB9eFwhcBzQB3hd0r7ANQBmNlBSf4IZvPcLjx9EMEP8VmC+pD8Dm4GfAd80s68k3QD8EPhFWGeNmR0q6X+AH5vZlZLGABvN7A8AkmYBJ5rZ8sopnpxraH4H5VztPjWz6eHnaQQJYwfhHHD5ZvY8gJltMbNNBNM6PWnBrOcrgX8Bh4fVpprZCjPbSjDt1qSwfFa173jGzCrM7GOCRNY/PO9fwu/6CFgCVCaoKWa2zsy2EMzh1ptgYcgBwH/C5UEuCcsrVU7YW+P1hf4DPCrpKiBvF8c4l1Z+B+Vc7bYmfC4Hamriq2kZl9rKq5+3ImG7gh3/XVafi8ySOG95eC4RrFd1fh11Ko/fiZmNknQEcCowXdIgM/uiljicS5nfQTmXIgvWs1om6VsAklpJagu8CZynYGHDrsCxwPtJnv4cSc3C51L7EKxI+iZwYfhd+wF7heW78i5wdNg8iKS2CU2Cu7IB6FC5IamPmb1nZj8H1rDjsjXONQhPUM6lx8XA9yXNBN4G9iRYk2gmwQzb/wR+YsFyCsmYT9A0+AowKmy6+39AXvhc6Gng0rCpsEZmthq4FHgyjO9dgqbC2rwInFnZSQL4fdiJYjZBgpyR5HU4lzSfzdy5DCXpUYLlL56NOxbn4uB3UM455zKS30E5lwRJ9xIsk57objN7JI54nGvKPEE555zLSN7E55xzLiN5gnLOOZeRPEE555zLSJ6gnHPOZSRPUM455zLS/wcKyPnnasKdJwAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x432 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "print(__doc__)\n",
    "\n",
    "# Code source: Gaël Varoquaux\n",
    "# Modified for documentation by Jaques Grobler\n",
    "# Modified for codeflare pipeline by Yuan-Chi Chang & Kun-Lung Wu\n",
    "# License: Same as original code creator\n",
    "\n",
    "import codeflare.pipelines.Datamodel as dm\n",
    "import codeflare.pipelines.Runtime as rt\n",
    "from codeflare.pipelines.Datamodel import Xy\n",
    "from codeflare.pipelines.Datamodel import XYRef\n",
    "from codeflare.pipelines.Runtime import ExecutionType\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "\n",
    "from sklearn import datasets\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn import datasets\n",
    "from sklearn.model_selection import KFold\n",
    "\n",
    "import ray\n",
    "ray.shutdown()\n",
    "ray.init()\n",
    "\n",
    "X_digits, y_digits = datasets.load_digits(return_X_y=True)\n",
    "\n",
    "pca = PCA()\n",
    "# set the tolerance to a large value to make the example faster\n",
    "logistic = LogisticRegression(max_iter=10000, tol=0.1)\n",
    "\n",
    "pipeline = dm.Pipeline()\n",
    "node_pca = dm.EstimatorNode('pca', pca)\n",
    "node_logistic = dm.EstimatorNode('logistic', logistic)\n",
    "\n",
    "pipeline.add_edge(node_pca, node_logistic)\n",
    "\n",
    "# input to pipeline\n",
    "pipeline_input = dm.PipelineInput()\n",
    "pipeline_input.add_xy_arg(node_pca, dm.Xy(X_digits, y_digits))\n",
    "\n",
    "# param_grid\n",
    "param_grid = {\n",
    "        'pca__n_components': [5, 15, 30, 45, 64],\n",
    "        'logistic__C': np.logspace(-4, 4, 4),\n",
    "    }\n",
    "\n",
    "pipeline_param = dm.PipelineParam.from_param_grid(param_grid)\n",
    "\n",
    "# default KFold for grid search\n",
    "k = 5\n",
    "kf = KFold(k)\n",
    "\n",
    "# execute CF pipeplie grid_search_cv\n",
    "result = rt.grid_search_cv(kf, pipeline, pipeline_input, pipeline_param)\n",
    "\n",
    "import statistics\n",
    "\n",
    "# pick the best mean' and best pipeline\n",
    "best_pipeline = None\n",
    "best_mean_scores = 0.0\n",
    "best_n_components = 0\n",
    "\n",
    "df = pd.DataFrame(columns =('n_components', 'mean_test_score', 'std_test_score'))\n",
    "\n",
    "for cv_pipeline, scores in result.items():\n",
    "    mean = statistics.mean(scores)\n",
    "    std = statistics.stdev(scores)\n",
    "    n_components = 0\n",
    "    params = {}\n",
    "    # get the 'n_components' value of the PCA in this cv_pipeline\n",
    "    for node_name, node in cv_pipeline.get_nodes().items():\n",
    "        params[node_name] = node.get_estimator().get_params()\n",
    "        if 'n_components' in params[node_name]:\n",
    "            n_components = params[node_name]['n_components']\n",
    "    assert(n_components > 0)\n",
    "    df = df.append({'n_components' : n_components, 'mean_test_score' : mean, 'std_test_score' : std}, ignore_index=True)\n",
    "    if mean > 0.92:\n",
    "        print(mean)\n",
    "        print(str(params))\n",
    "        \n",
    "    if mean > best_mean_scores:\n",
    "        best_pipeline = cv_pipeline\n",
    "        best_mean_scores = mean\n",
    "        best_n_components = n_components\n",
    "        \n",
    "\n",
    "# Plot the PCA spectrum\n",
    "pca.fit(X_digits)\n",
    "\n",
    "fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, figsize=(6, 6))\n",
    "ax0.plot(np.arange(1, pca.n_components_ + 1),\n",
    "         pca.explained_variance_ratio_, '+', linewidth=2)\n",
    "ax0.set_ylabel('PCA explained variance ratio')\n",
    "\n",
    "# plot a vertical line with the n_components chosen from the best_pipeline\n",
    "\n",
    "ax0.axvline(best_n_components,\n",
    "            linestyle=':', label='n_components chosen')\n",
    "\n",
    "ax0.legend(prop=dict(size=12))\n",
    "\n",
    "# For each number of components, find the best classifier results\n",
    "\n",
    "components_col = 'n_components'\n",
    "best_clfs = df.groupby(components_col).apply(\n",
    "    lambda g: g.nlargest(1, 'mean_test_score'))\n",
    "\n",
    "\n",
    "best_clfs.plot(x=components_col, y='mean_test_score', yerr='std_test_score',\n",
    "               legend=False, ax=ax1)\n",
    "ax1.set_ylabel('Classification accuracy (val)')\n",
    "ax1.set_xlabel('n_components')\n",
    "\n",
    "plt.xlim(-1, 70)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# Due to the differences in split, the codeflare execution produces the best mean\n",
    "# test score with a different n_components for PCA than that from the original Sklearn\n",
    "# execution. The 2nd best in codeflare, nevertheless, matches the original\n",
    "# Sklearn execution.\n",
    "\n",
    "ray.shutdown()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
